1use std::collections::HashMap;
7
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10
11use crate::backend::obj::MetaMapType;
12
13pub(crate) fn is_false(v: &bool) -> bool {
16 !v
17}
18
19pub(crate) fn is_zero_f64(v: &f64) -> bool {
20 *v == 0.0
21}
22
23pub(crate) fn is_zero_f32(v: &f32) -> bool {
24 *v == 0.0
25}
26
27pub(crate) fn is_zero_i32(v: &i32) -> bool {
28 *v == 0
29}
30
31#[derive(Debug, Clone, Default, Serialize, Deserialize)]
37pub struct SettingsType {
38 #[serde(rename = "app:*", default, skip_serializing_if = "is_false")]
40 pub app_clear: bool,
41
42 #[serde(rename = "app:globalhotkey", default, skip_serializing_if = "String::is_empty")]
43 pub app_global_hotkey: String,
44
45 #[serde(rename = "app:dismissarchitecturewarning", default, skip_serializing_if = "is_false")]
46 pub app_dismiss_architecture_warning: bool,
47
48 #[serde(rename = "app:defaultnewblock", default, skip_serializing_if = "String::is_empty")]
49 pub app_default_new_block: String,
50
51 #[serde(rename = "app:showoverlayblocknums", default, skip_serializing_if = "Option::is_none")]
52 pub app_show_overlay_block_nums: Option<bool>,
53
54 #[serde(rename = "term:*", default, skip_serializing_if = "is_false")]
56 pub term_clear: bool,
57
58 #[serde(rename = "term:fontsize", default, skip_serializing_if = "is_zero_f64")]
59 pub term_font_size: f64,
60
61 #[serde(rename = "term:fontfamily", default, skip_serializing_if = "String::is_empty")]
62 pub term_font_family: String,
63
64 #[serde(rename = "term:theme", default, skip_serializing_if = "String::is_empty")]
65 pub term_theme: String,
66
67 #[serde(rename = "term:disablewebgl", default, skip_serializing_if = "is_false")]
68 pub term_disable_web_gl: bool,
69
70 #[serde(rename = "term:localshellpath", default, skip_serializing_if = "String::is_empty")]
71 pub term_local_shell_path: String,
72
73 #[serde(rename = "term:localshellopts", default, skip_serializing_if = "Vec::is_empty")]
74 pub term_local_shell_opts: Vec<String>,
75
76 #[serde(rename = "term:scrollback", default, skip_serializing_if = "Option::is_none")]
77 pub term_scrollback: Option<i64>,
78
79 #[serde(rename = "term:copyonselect", default, skip_serializing_if = "Option::is_none")]
80 pub term_copy_on_select: Option<bool>,
81
82 #[serde(rename = "term:transparency", default, skip_serializing_if = "Option::is_none")]
83 pub term_transparency: Option<f64>,
84
85 #[serde(rename = "term:allowbracketedpaste", default, skip_serializing_if = "Option::is_none")]
86 pub term_allow_bracketed_paste: Option<bool>,
87
88 #[serde(rename = "term:shiftenternewline", default, skip_serializing_if = "Option::is_none")]
89 pub term_shift_enter_newline: Option<bool>,
90
91 #[serde(rename = "term:agentmaxruntimehours", default, skip_serializing_if = "is_zero_f64")]
94 pub term_agent_max_runtime_hours: f64,
95
96 #[serde(rename = "term:agentidletimeoutmins", default, skip_serializing_if = "is_zero_f64")]
99 pub term_agent_idle_timeout_mins: f64,
100
101 #[serde(rename = "cmd:env", default, skip_serializing_if = "HashMap::is_empty")]
103 pub cmd_env: HashMap<String, String>,
104
105 #[serde(rename = "blockheader:*", default, skip_serializing_if = "is_false")]
107 pub block_header_clear: bool,
108
109 #[serde(rename = "blockheader:showblockids", default, skip_serializing_if = "is_false")]
110 pub block_header_show_block_ids: bool,
111
112 #[serde(rename = "preview:showhiddenfiles", default, skip_serializing_if = "Option::is_none")]
114 pub preview_show_hidden_files: Option<bool>,
115
116 #[serde(rename = "tab:preset", default, skip_serializing_if = "String::is_empty")]
118 pub tab_preset: String,
119
120 #[serde(rename = "widget:*", default, skip_serializing_if = "is_false")]
122 pub widget_clear: bool,
123
124 #[serde(rename = "widget:showhelp", default, skip_serializing_if = "Option::is_none")]
125 pub widget_show_help: Option<bool>,
126
127 #[serde(rename = "widget:icononly", default, skip_serializing_if = "Option::is_none")]
128 pub widget_icon_only: Option<bool>,
129
130 #[serde(rename = "window:*", default, skip_serializing_if = "is_false")]
132 pub window_clear: bool,
133
134 #[serde(rename = "window:transparent", default, skip_serializing_if = "is_false")]
135 pub window_transparent: bool,
136
137 #[serde(rename = "window:blur", default, skip_serializing_if = "is_false")]
138 pub window_blur: bool,
139
140 #[serde(rename = "window:opacity", default, skip_serializing_if = "Option::is_none")]
141 pub window_opacity: Option<f64>,
142
143 #[serde(rename = "window:bgcolor", default, skip_serializing_if = "String::is_empty")]
144 pub window_bg_color: String,
145
146 #[serde(rename = "window:reducedmotion", default, skip_serializing_if = "is_false")]
147 pub window_reduced_motion: bool,
148
149 #[serde(rename = "window:tilegapsize", default, skip_serializing_if = "Option::is_none")]
150 pub window_tile_gap_size: Option<i64>,
151
152 #[serde(rename = "window:showmenubar", default, skip_serializing_if = "is_false")]
153 pub window_show_menu_bar: bool,
154
155 #[serde(rename = "window:nativetitlebar", default, skip_serializing_if = "is_false")]
156 pub window_native_title_bar: bool,
157
158 #[serde(rename = "window:disablehardwareacceleration", default, skip_serializing_if = "is_false")]
159 pub window_disable_hardware_acceleration: bool,
160
161 #[serde(rename = "window:maxtabcachesize", default, skip_serializing_if = "is_zero_i32")]
162 pub window_max_tab_cache_size: i32,
163
164 #[serde(rename = "window:magnifiedblockopacity", default, skip_serializing_if = "Option::is_none")]
165 pub window_magnified_block_opacity: Option<f64>,
166
167 #[serde(rename = "window:magnifiedblocksize", default, skip_serializing_if = "Option::is_none")]
168 pub window_magnified_block_size: Option<f64>,
169
170 #[serde(rename = "window:magnifiedblockblurprimarypx", default, skip_serializing_if = "Option::is_none")]
171 pub window_magnified_block_blur_primary_px: Option<i64>,
172
173 #[serde(rename = "window:magnifiedblockblursecondarypx", default, skip_serializing_if = "Option::is_none")]
174 pub window_magnified_block_blur_secondary_px: Option<i64>,
175
176 #[serde(rename = "window:confirmclose", default, skip_serializing_if = "is_false")]
177 pub window_confirm_close: bool,
178
179 #[serde(rename = "window:savelastwindow", default, skip_serializing_if = "is_false")]
180 pub window_save_last_window: bool,
181
182 #[serde(rename = "window:dimensions", default, skip_serializing_if = "String::is_empty")]
183 pub window_dimensions: String,
184
185 #[serde(rename = "window:zoom", default, skip_serializing_if = "Option::is_none")]
186 pub window_zoom: Option<f64>,
187
188 #[serde(rename = "telemetry:*", default, skip_serializing_if = "is_false")]
190 pub telemetry_clear: bool,
191
192 #[serde(rename = "telemetry:enabled", default, skip_serializing_if = "is_false")]
193 pub telemetry_enabled: bool,
194
195 #[serde(rename = "telemetry:interval", default, skip_serializing_if = "is_zero_f64")]
196 pub telemetry_interval: f64,
197
198 #[serde(rename = "telemetry:numpoints", default, skip_serializing_if = "Option::is_none")]
199 pub telemetry_numpoints: Option<i64>,
200
201 #[serde(rename = "conn:*", default, skip_serializing_if = "is_false")]
203 pub conn_clear: bool,
204
205 #[serde(rename = "network:lan_discovery", default, skip_serializing_if = "is_false")]
207 pub network_lan_discovery: bool,
208
209 #[serde(rename = "voice:enabled", default, skip_serializing_if = "Option::is_none")]
219 pub voice_enabled: Option<bool>,
220
221 #[serde(rename = "voice:engine", default, skip_serializing_if = "Option::is_none")]
226 pub voice_engine: Option<String>,
227
228 #[serde(rename = "voice:groqApiKey", default, skip_serializing_if = "Option::is_none")]
231 pub voice_groq_api_key: Option<String>,
232
233 #[serde(rename = "voice:whisperCliPath", default, skip_serializing_if = "Option::is_none")]
237 pub voice_whisper_cli_path: Option<String>,
238 #[serde(rename = "voice:whisperModel", default, skip_serializing_if = "Option::is_none")]
241 pub voice_whisper_model: Option<String>,
242 #[serde(rename = "voice:whisperModelPath", default, skip_serializing_if = "Option::is_none")]
243 pub voice_whisper_model_path: Option<String>,
244
245 #[serde(rename = "notify:sounds:enabled", default, skip_serializing_if = "Option::is_none")]
253 pub notify_sounds_enabled: Option<bool>,
254
255 #[serde(rename = "notify:sounds:volume", default, skip_serializing_if = "Option::is_none")]
257 pub notify_sounds_volume: Option<f32>,
258
259 #[serde(rename = "notify:sounds:suppresswhenfocused", default, skip_serializing_if = "Option::is_none")]
262 pub notify_sounds_suppress_when_focused: Option<bool>,
263
264 #[serde(rename = "notify:sound:agent.turn.complete", default, skip_serializing_if = "Option::is_none")]
266 pub notify_sound_agent_turn_complete: Option<bool>,
267
268 #[serde(rename = "notify:sound:agent.turn.error", default, skip_serializing_if = "Option::is_none")]
269 pub notify_sound_agent_turn_error: Option<bool>,
270
271 #[serde(rename = "notify:sound:agent.turn.interrupted", default, skip_serializing_if = "Option::is_none")]
272 pub notify_sound_agent_turn_interrupted: Option<bool>,
273
274 #[serde(rename = "notify:sound:agent.message.accepted", default, skip_serializing_if = "Option::is_none")]
275 pub notify_sound_agent_message_accepted: Option<bool>,
276
277 #[serde(rename = "notify:sound:agent.message.rejected", default, skip_serializing_if = "Option::is_none")]
278 pub notify_sound_agent_message_rejected: Option<bool>,
279
280 #[serde(rename = "notify:tooltones:enabled", default, skip_serializing_if = "Option::is_none")]
287 pub notify_tooltones_enabled: Option<bool>,
288
289 #[serde(rename = "notify:tooltones:volume", default, skip_serializing_if = "Option::is_none")]
292 pub notify_tooltones_volume: Option<f32>,
293
294 #[serde(rename = "notify:tooltones:scope", default, skip_serializing_if = "Option::is_none")]
298 pub notify_tooltones_scope: Option<String>,
299
300 #[serde(flatten, default, skip_serializing_if = "HashMap::is_empty")]
303 pub extra: HashMap<String, serde_json::Value>,
304}
305
306#[derive(Debug, Clone, Default, Serialize, Deserialize)]
310pub struct MimeTypeConfigType {
311 #[serde(default, skip_serializing_if = "String::is_empty")]
312 pub icon: String,
313
314 #[serde(default, skip_serializing_if = "String::is_empty")]
315 pub color: String,
316}
317
318#[derive(Debug, Clone, Default, Serialize, Deserialize)]
320pub struct FileDef {
321 #[serde(default, skip_serializing_if = "String::is_empty")]
322 pub content: String,
323
324 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
325 pub meta: HashMap<String, Value>,
326}
327
328#[derive(Debug, Clone, Default, Serialize, Deserialize)]
330pub struct BlockDef {
331 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
332 pub files: HashMap<String, FileDef>,
333
334 #[serde(default, skip_serializing_if = "HashMap::is_empty")]
335 pub meta: MetaMapType,
336}
337
338#[derive(Debug, Clone, Default, Serialize, Deserialize)]
340pub struct WidgetConfigType {
341 #[serde(rename = "display:order", default, skip_serializing_if = "is_zero_f64")]
342 pub display_order: f64,
343
344 #[serde(rename = "display:hidden", default, skip_serializing_if = "is_false")]
345 pub display_hidden: bool,
346
347 #[serde(rename = "display:pinned", default, skip_serializing_if = "is_false")]
350 pub display_pinned: bool,
351
352 #[serde(default, skip_serializing_if = "String::is_empty")]
353 pub icon: String,
354
355 #[serde(default, skip_serializing_if = "String::is_empty")]
356 pub color: String,
357
358 #[serde(default, skip_serializing_if = "String::is_empty")]
359 pub label: String,
360
361 #[serde(default, skip_serializing_if = "String::is_empty")]
362 pub description: String,
363
364 #[serde(default, skip_serializing_if = "is_false")]
365 pub magnified: bool,
366
367 #[serde(rename = "blockdef", default)]
368 pub block_def: BlockDef,
369}
370
371#[derive(Debug, Clone, Default, Serialize, Deserialize)]
373pub struct TermThemeType {
374 #[serde(rename = "display:name", default, skip_serializing_if = "String::is_empty")]
375 pub display_name: String,
376
377 #[serde(rename = "display:order", default, skip_serializing_if = "is_zero_f64")]
378 pub display_order: f64,
379
380 #[serde(default, skip_serializing_if = "String::is_empty")]
381 pub black: String,
382 #[serde(default, skip_serializing_if = "String::is_empty")]
383 pub red: String,
384 #[serde(default, skip_serializing_if = "String::is_empty")]
385 pub green: String,
386 #[serde(default, skip_serializing_if = "String::is_empty")]
387 pub yellow: String,
388 #[serde(default, skip_serializing_if = "String::is_empty")]
389 pub blue: String,
390 #[serde(default, skip_serializing_if = "String::is_empty")]
391 pub magenta: String,
392 #[serde(default, skip_serializing_if = "String::is_empty")]
393 pub cyan: String,
394 #[serde(default, skip_serializing_if = "String::is_empty")]
395 pub white: String,
396
397 #[serde(rename = "brightBlack", default, skip_serializing_if = "String::is_empty")]
398 pub bright_black: String,
399 #[serde(rename = "brightRed", default, skip_serializing_if = "String::is_empty")]
400 pub bright_red: String,
401 #[serde(rename = "brightGreen", default, skip_serializing_if = "String::is_empty")]
402 pub bright_green: String,
403 #[serde(rename = "brightYellow", default, skip_serializing_if = "String::is_empty")]
404 pub bright_yellow: String,
405 #[serde(rename = "brightBlue", default, skip_serializing_if = "String::is_empty")]
406 pub bright_blue: String,
407 #[serde(rename = "brightMagenta", default, skip_serializing_if = "String::is_empty")]
408 pub bright_magenta: String,
409 #[serde(rename = "brightCyan", default, skip_serializing_if = "String::is_empty")]
410 pub bright_cyan: String,
411 #[serde(rename = "brightWhite", default, skip_serializing_if = "String::is_empty")]
412 pub bright_white: String,
413
414 #[serde(default, skip_serializing_if = "String::is_empty")]
415 pub gray: String,
416 #[serde(rename = "cmdtext", default, skip_serializing_if = "String::is_empty")]
417 pub cmd_text: String,
418 #[serde(default, skip_serializing_if = "String::is_empty")]
419 pub foreground: String,
420 #[serde(rename = "selectionBackground", default, skip_serializing_if = "String::is_empty")]
421 pub selection_background: String,
422 #[serde(default, skip_serializing_if = "String::is_empty")]
423 pub background: String,
424 #[serde(default, skip_serializing_if = "String::is_empty")]
425 pub cursor: String,
426}
427
428#[derive(Debug, Clone, Default, Serialize, Deserialize)]
430pub struct WebBookmark {
431 #[serde(default)]
432 pub url: String,
433
434 #[serde(default, skip_serializing_if = "String::is_empty")]
435 pub title: String,
436
437 #[serde(default, skip_serializing_if = "String::is_empty")]
438 pub icon: String,
439
440 #[serde(rename = "iconcolor", default, skip_serializing_if = "String::is_empty")]
441 pub icon_color: String,
442
443 #[serde(rename = "iconurl", default, skip_serializing_if = "String::is_empty")]
444 pub icon_url: String,
445
446 #[serde(rename = "display:order", default, skip_serializing_if = "is_zero_f64")]
447 pub display_order: f64,
448}
449
450#[derive(Debug, Clone, Default, Serialize, Deserialize)]
453pub struct ConnKeywords {
454 #[serde(rename = "conn:shellpath", default, skip_serializing_if = "String::is_empty")]
456 pub conn_shell_path: String,
457
458 #[serde(rename = "conn:ignoresshconfig", default, skip_serializing_if = "Option::is_none")]
459 pub conn_ignore_ssh_config: Option<bool>,
460
461 #[serde(rename = "display:hidden", default, skip_serializing_if = "Option::is_none")]
463 pub display_hidden: Option<bool>,
464
465 #[serde(rename = "display:order", default, skip_serializing_if = "is_zero_f32")]
466 pub display_order: f32,
467
468 #[serde(rename = "term:*", default, skip_serializing_if = "is_false")]
470 pub term_clear: bool,
471
472 #[serde(rename = "term:fontsize", default, skip_serializing_if = "is_zero_f64")]
473 pub term_font_size: f64,
474
475 #[serde(rename = "term:fontfamily", default, skip_serializing_if = "String::is_empty")]
476 pub term_font_family: String,
477
478 #[serde(rename = "term:theme", default, skip_serializing_if = "String::is_empty")]
479 pub term_theme: String,
480
481 #[serde(rename = "cmd:env", default, skip_serializing_if = "HashMap::is_empty")]
483 pub cmd_env: HashMap<String, String>,
484
485 #[serde(rename = "cmd:initscript", default, skip_serializing_if = "String::is_empty")]
486 pub cmd_init_script: String,
487
488 #[serde(rename = "cmd:initscript.sh", default, skip_serializing_if = "String::is_empty")]
489 pub cmd_init_script_sh: String,
490
491 #[serde(rename = "cmd:initscript.bash", default, skip_serializing_if = "String::is_empty")]
492 pub cmd_init_script_bash: String,
493
494 #[serde(rename = "cmd:initscript.zsh", default, skip_serializing_if = "String::is_empty")]
495 pub cmd_init_script_zsh: String,
496
497 #[serde(rename = "cmd:initscript.pwsh", default, skip_serializing_if = "String::is_empty")]
498 pub cmd_init_script_pwsh: String,
499
500 #[serde(rename = "cmd:initscript.fish", default, skip_serializing_if = "String::is_empty")]
501 pub cmd_init_script_fish: String,
502
503 #[serde(rename = "ssh:user", default, skip_serializing_if = "Option::is_none")]
505 pub ssh_user: Option<String>,
506
507 #[serde(rename = "ssh:hostname", default, skip_serializing_if = "Option::is_none")]
508 pub ssh_hostname: Option<String>,
509
510 #[serde(rename = "ssh:port", default, skip_serializing_if = "Option::is_none")]
511 pub ssh_port: Option<String>,
512
513 #[serde(rename = "ssh:identityfile", default, skip_serializing_if = "Vec::is_empty")]
514 pub ssh_identity_file: Vec<String>,
515
516 #[serde(rename = "ssh:batchmode", default, skip_serializing_if = "Option::is_none")]
517 pub ssh_batch_mode: Option<bool>,
518
519 #[serde(rename = "ssh:pubkeyauthentication", default, skip_serializing_if = "Option::is_none")]
520 pub ssh_pubkey_authentication: Option<bool>,
521
522 #[serde(rename = "ssh:passwordauthentication", default, skip_serializing_if = "Option::is_none")]
523 pub ssh_password_authentication: Option<bool>,
524
525 #[serde(rename = "ssh:kbdinteractiveauthentication", default, skip_serializing_if = "Option::is_none")]
526 pub ssh_kbd_interactive_authentication: Option<bool>,
527
528 #[serde(rename = "ssh:preferredauthentications", default, skip_serializing_if = "Vec::is_empty")]
529 pub ssh_preferred_authentications: Vec<String>,
530
531 #[serde(rename = "ssh:addkeystoagent", default, skip_serializing_if = "Option::is_none")]
532 pub ssh_add_keys_to_agent: Option<bool>,
533
534 #[serde(rename = "ssh:identityagent", default, skip_serializing_if = "Option::is_none")]
535 pub ssh_identity_agent: Option<String>,
536
537 #[serde(rename = "ssh:identitiesonly", default, skip_serializing_if = "Option::is_none")]
538 pub ssh_identities_only: Option<bool>,
539
540 #[serde(rename = "ssh:proxyjump", default, skip_serializing_if = "Vec::is_empty")]
541 pub ssh_proxy_jump: Vec<String>,
542
543 #[serde(rename = "ssh:userknownhostsfile", default, skip_serializing_if = "Vec::is_empty")]
544 pub ssh_user_known_hosts_file: Vec<String>,
545
546 #[serde(rename = "ssh:globalknownhostsfile", default, skip_serializing_if = "Vec::is_empty")]
547 pub ssh_global_known_hosts_file: Vec<String>,
548}
549
550#[derive(Debug, Clone, Default, Serialize, Deserialize)]
552pub struct ConfigError {
553 pub file: String,
554 pub err: String,
555}
556
557#[allow(dead_code)]
559#[derive(Debug, Clone, Default, Serialize, Deserialize)]
560pub struct WebhookConfigType {
561 #[serde(default)]
562 pub version: String,
563
564 #[serde(rename = "workspaceId", default)]
565 pub workspace_id: String,
566
567 #[serde(rename = "authToken", default)]
568 pub auth_token: String,
569
570 #[serde(rename = "cloudEndpoint", default)]
571 pub cloud_endpoint: String,
572
573 #[serde(default)]
574 pub enabled: bool,
575
576 #[serde(default)]
577 pub terminals: Vec<String>,
578}
579
580#[derive(Debug, Clone, Default, Serialize, Deserialize)]
585pub struct FullConfigType {
586 #[serde(default)]
587 pub settings: SettingsType,
588
589 #[serde(rename = "mimetypes", default)]
590 pub mime_types: HashMap<String, MimeTypeConfigType>,
591
592 #[serde(rename = "defaultwidgets", default)]
593 pub default_widgets: HashMap<String, WidgetConfigType>,
594
595 #[serde(default)]
596 pub widgets: HashMap<String, WidgetConfigType>,
597
598 #[serde(default)]
599 pub presets: HashMap<String, MetaMapType>,
600
601 #[serde(rename = "termthemes", default)]
602 pub term_themes: HashMap<String, TermThemeType>,
603
604 #[serde(default)]
605 pub connections: HashMap<String, ConnKeywords>,
606
607 #[serde(default)]
608 pub bookmarks: HashMap<String, WebBookmark>,
609
610 #[serde(rename = "configerrors", default, skip_serializing_if = "Vec::is_empty")]
611 pub config_errors: Vec<ConfigError>,
612}